﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.Modeling.Validation;
using System.Windows.Data;
using System.Reflection;
using Microsoft.VisualStudio.Modeling;
using System.Collections;
using devtm.Templates;
using Microsoft.VisualStudio.Modeling.Diagrams;
using CodeDomHelper.Types;
using devtm.Editor.TypeSelector;
using System.Text.RegularExpressions;
using System.Diagnostics;
using devtm.Editor.TypeSelector.Assemblies;
using VSLangProj;
using System.IO;
using devtm.Editor.TypeSelector.Dsl2Dte;
using Microsoft.RestrictedUsage.CSharp.Semantics;
using CSharpParser.SCharpType;
using CustomTypes.Interfaces;



namespace devtm.AutoMapper
{

    [ValidationState(ValidationState.Enabled)]
    public partial class Mapper
    {


        private const string Pattern1 = @"[^\w\d]*";
        private static Regex regExCsharpName = new Regex(Pattern1, RegexOptions.Compiled);
        private static bool StopTest;
        private static Hashtable refs = null;
        private static bool inError = false;
        public string ItemTested;

        CSharpType sharpTypeSource = null;
        CSharpType sharpTypeDestination = null;
       


        [ValidationMethod(ValidationCategories.Open | ValidationCategories.Save)]
        private void ValidateAttributeNameAsValidIdentifier(ValidationContext context)
        {

            bool inError = false;

            Hashtable ListRefs = refs ?? (refs = LoadPaths(context));
            TypeExpression typeExpressionSource = null;
            CustomType TypeStructureSource = null;
            TypeExpression typeExpressionTarget = null;
            CustomType TypeStructureTarget = null;

            try
            {

                #region Find Type

                // On cherche les types dans les assemblies
                typeExpressionSource = TypeExpression.Analyse(this.TypeSource);
                TypeStructureSource = TypeRepository.GetType(typeExpressionSource);
                typeExpressionTarget = TypeExpression.Analyse(this.TypeDestination);
                TypeStructureTarget = TypeRepository.GetType(typeExpressionTarget);

                if (TypeStructureSource == null)
                {
                    string assName = typeExpressionSource.AssemblyName;
                    if (!TypeRepository.Contains(assName))
                        context.LogError("Assembly name from source can't be resolved", "1", this.MappingSource.TypeElement);
                    else
                        context.LogError(string.Format("the type source name '{0}' can't be found", typeExpressionSource.FullName), "1", this.MappingSource.TypeElement);
                }

                if (TypeStructureTarget == null)
                {
                    string assName = typeExpressionTarget.AssemblyName;
                    if (!TypeRepository.Contains(assName))
                        context.LogError("Assembly name from target can't be resolved", "1", this.MappingDestination.TypeElement);
                    else
                        context.LogError(string.Format("the type target name '{0}' can't be found", typeExpressionTarget.FullName), "1", this.MappingDestination.TypeElement);
                }

                if (TypeStructureSource == null || TypeStructureTarget == null)
                    return;

                #endregion





                if (inError)
                {
                    sharpTypeSource = null;
                    sharpTypeDestination = null;
                    return;
                }





                using (Resolver r = new Resolver(ListRefs))
                {


                    if (context.Categories == ValidationCategories.Save)
                    {

                        if (this.MappingSource != null)
                            SetTypeElementProperties(this.MappingSource.TypeElement, context);


                        if (this.MappingDestination != null)
                            SetTypeElementProperties(this.MappingDestination.TypeElement, context);


                        if (SourceTypes.Errors.Count != 0)
                            foreach (ContextTypeError item in SourceTypes.Errors)
                                context.LogWarning(item.Description, "1");


                        using (Transaction t = Store.TransactionManager.BeginTransaction("Update Property"))
                        {

                            if (this.MappingModel.Mappers.FirstOrDefault() == this)
                            {

                                inError = false;

                                ReferenceTypeProvider.CashAssemblies.Clear();
                                StHostingProject.CashAssemblies.Clear();
                                SetRecursifOff();
                                Mapper.StopTest = false;
                                ContainerTypes.PutInCache(ContainerTypes.GetTypes(this.Store, null).ToList());

                            }

                            if (inError)
                                return;

                            ItemTested = string.Empty;
                            CheckRecursifProperties(this, new Stack<Mapper>());

                            ItemTested = string.Empty;
                            CheckRecursifFields(this, new Queue<Mapper>());

                            t.Commit();

                        }
                    }

                    ItemTested = string.Empty;

                    if (StopTest)
                        return;

                    if (!CheckProperties(context))
                        return;



                    if (this.MappingDestination != null && this.MappingDestination.TypeElement != null)
                    {

                        TypeElement ee = this.MappingDestination.TypeElement;

                        if (!this.CustomConstructor)
                            if (ee.IsAbstract || ee.IsInterface)
                                context.LogError("the target type is abstract type, yous must set to enable the Custom Constructor parameter", "2", this);

                    }

                }

            }
            catch (Exception e)
            {

                inError = true;

                StackTrace trace = new StackTrace(e, true);
                string msg = "Exception throwed on mapper '" + this.Name + "'";

                if (!string.IsNullOrEmpty(ItemTested))
                    msg += " at item " + ItemTested;

                foreach (StackFrame item in trace.GetFrames())
                    msg += " method " + item.GetMethod().ToString() + " offset : " + item.GetNativeOffset().ToString() + "\n";

                context.LogError("(please send this message to gaelgael5@gmail.com)" + msg, "Validation error");

                throw;

            }
            finally
            {

                ItemTested = string.Empty;
                sharpTypeSource = null;
                sharpTypeDestination = null;

                foreach (TypeDiscoveryError item in TypeHelper.Errors)
                {
                    if (item.Message.Contains("devtm.Editor.TypeSelector.Dsl2Dte.TypeDiscoveryError"))
                    {
                        context.LogError(item.Message + "Rebuild the project for resolve the issue", "Validation");
                    }
                    else
                    {
                        context.LogError(item.Message, "Validation");
                    }
                    StopTest = true;
                }
                
            }

        }

        private HashSet<string> GetHashsetList(CSharpType type)
        {

            HashSet<string> lst = new HashSet<string>();

            foreach (CSharpMember item in type.Members)
                lst.Add(item.Name.Text);

            return lst;

        }

     
        private Hashtable LoadPaths(ValidationContext context)
        {

            Hashtable ListRefs = new Hashtable();

            string dd1 = Environment.GetFolderPath(Environment.SpecialFolder.Windows).ToLower();
            string dd2 = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86).ToLower();
            var sln = new VisualStudio.ParsingSolution.Solution(Store2DTE.GetSolutionForStore(this.Store));
            try
            {

                foreach (VisualStudio.ParsingSolution.Project prj in sln.GetItem<VisualStudio.ParsingSolution.Project>())
                {

                    References references = prj.GetReferences();
                    if (references != null)
                    {
                        foreach (Reference refs in references)
                        {

                            string n = refs.Name;
                            string p = refs.Path.ToLower();


                            if (string.IsNullOrEmpty(p))
                                continue;

                            try
                            {
                                File.GetLastWriteTime(p);
                            }
                            catch (Exception)
                            {
                                continue;
                            }


                            if (p.StartsWith(dd1) || p.StartsWith(dd2))
                                continue;

                            if (ListRefs.ContainsKey(n))
                            {
                                string p2 = ListRefs[n] as string;

                                if (p2 != p)
                                {

                                    DateTime d1 = File.GetLastWriteTime(p2);
                                    DateTime d2 = File.GetLastWriteTime(p);

                                    if (d2 > d1)
                                        ListRefs[n] = p2;

                                }
                            }
                            else
                            {
                                ListRefs.Add(n, p);
                            }

                        }
                    }

                }
            }
            catch (Exception e)
            {

                StackTrace trace = new StackTrace(e, true);
                var t = trace.GetFrame(0);
                context.LogError("(please send this message to gaelgael5@gmail.com)" + e.Message + " method : " + t.GetMethod().ToString() + " offset : " + t.GetNativeOffset().ToString(), "Validation error");

                throw;

            }
            return ListRefs;
        }

        private void CheckRecursifProperties(Mapper m, Stack<Mapper> queue)
        {

            queue.Push(m);

            foreach (ItemMap item in m.ItemMaps)
            {

                this.ItemTested = item.Label;
                if (!(item.SourceIsClass || item.SourceIsInterface) || item.SourceType == "System.String" || item.IsRecursif)
                    continue;

                string type = string.Empty;

                if (item.SourceIsEnumerable)
                {
                    TypeExpression t = BuildTypeExpression.Analyse(item.SourceType);
                    type = t.IsGeneric ? t.SubType.AssemblyQualifiedName : t.AssemblyQualifiedName;
                }
                else
                    type = item.SourceType;

                Mapper m2 = this.MappingModel.FindMapperFor(type);
                if (m2 != null)
                {
                    if (queue.Contains(m2))
                    {                            
                        item.IsRecursif = true;
                        continue;
                    }

                    if (!item.IsRecursif)
                        CheckRecursifProperties(m2, queue);
                }
            }

            queue.Pop();
        }


        private void CheckRecursifFields(Mapper m, Queue<Mapper> queue)
        {

            queue.Enqueue(m);

            foreach (ItemMap item in m.ItemMaps)
            {

                this.ItemTested = item.Label;

                if (!(item.SourceIsClass || item.SourceIsInterface) || item.SourceType == "System.String" || item.IsRecursif)
                    continue;

                string type = string.Empty;

                if (item.SourceIsEnumerable)
                {
                    TypeExpression t = BuildTypeExpression.Analyse(item.SourceType);
                    type = t.IsGeneric ? t.SubType.AssemblyQualifiedName : t.AssemblyQualifiedName;
                }
                else
                    type = item.SourceType;

                Mapper m2 = this.MappingModel.FindMapperFor(type);
                if (m2 != null)
                {
                    if (queue.Contains(m2))
                    {
                        item.IsRecursif = true;
                        continue;
                    }

                    if (!item.IsRecursif)
                        CheckRecursifFields(m2, queue);
                }
            }

            queue.Dequeue();

        }



        private void SetRecursifOff()
        {

            foreach (Mapper m in this.MappingModel.Mappers)
            {

                foreach (ItemMap p in m.ItemMaps)
                {
                    if (p.IsRecursif)
                        p.IsRecursif = false;
                }

            }

        }

        
        private void SetTypeElementProperties(TypeElement e, ValidationContext context)
        {

            Type type = e.Type;

            if (SourceTypes.Errors.Count > 0)
                foreach (var err in SourceTypes.Errors)
                {

                    if (err.Exception != null)
                        context.LogWarning(err.Description + ". " + err.Exception.Message, "1");
                    else                    
                        context.LogWarning(err.Description + ". ", "1");                    
                }
            
            if (type != null)
                using (Transaction t = Store.TransactionManager.BeginTransaction("Update TypeElement"))
                {

                    e.Namespace = string.Empty;
                    e.FullName = string.Empty;

                    e.IsAbstract = type.IsAbstract;                
                    e.IsAnsiClass = type.IsAnsiClass;
                    e.IsArray = type.IsArray;
                    e.IsClass = type.IsClass;
                    e.IsEnum = type.IsEnum;
                    e.IsInterface = type.IsInterface;
                    e.IsNested = type.IsNested;
                    e.IsPublic = type.IsPublic;
                    e.IsSealed = type.IsSealed;
                    e.IsValueType = type.IsValueType;
                    e.IsSerializable = type.IsSerializable;
                    e.IsEnumerable = type.GetInterface("IEnumerable", true) != null;

                    if (e.IsEnumerable)
                    {
                        Type typeEnumerable = FindItemFromIEnumerable(type);

                        if (typeEnumerable != null)
                            e.ItemType = typeEnumerable.AssemblyQualifiedName;

                        else
                            e.ItemType = string.Empty;

                    }

                    e.Namespace = type.Namespace;
                    e.FullName = type.FullName;
                    e.Name = type.Name;

                    t.Commit();

                }
            }


        #region ItemMap

        #region Valide format des properties

        /// <summary>
        /// Suit le file des membres
        /// </summary>
        /// <param name="context"></param>
        /// <param name="item"></param>
        /// <param name="itemName"></param>
        /// <param name="itemType"></param>
        /// <param name="source"></param>
        private bool TestItemMap(ValidationContext context, ItemMap item, string itemName, string itemType, bool source)
        {

            MemberInfoDesc p1 = null;

            if (source)
            {
                if (item.Mapper.MappingSource != null
                    && item.Mapper.MappingSource.TypeElement != null
                    && item.Mapper.MappingSource.TypeElement.Type != null)
                {
                    Type tty = item.Mapper.MappingSource.TypeElement.Type;
                    p1 = ResolveProperty(tty, itemName).LastOrDefault();
                }

                if (p1 == null)
                {
                    string assemblyName = TypeExpression.Analyse(item.Mapper.MappingSource.TypeElement.Name).AssemblyQualifiedNameUltraShort;
                    context.LogError(string.Format("the source {0} is not resolvable. Please check the source assembly {1}", item.Mapper.MappingSource.TypeElement.Name, assemblyName), "1", item);
                    Mapper.StopTest = true;

                    return false;
                }
                else if (p1.Member == null) if (p1.Member == null)
                    {
                        context.LogError(string.Format("mismatch on the source name '{0}'.", p1.PropertyName), "1", item);
                        return false;
                    }

            }
            else
            {

                if (item.Mapper.MappingDestination != null
                    && item.Mapper.MappingDestination.TypeElement != null
                    && item.Mapper.MappingDestination.TypeElement.Type != null)

                    p1 = ResolveProperty(item.Mapper.MappingDestination.TypeElement.Type, itemName).LastOrDefault();

                if (p1 == null)
                {
                    string assemblyName = TypeExpression.Analyse(item.Mapper.MappingDestination.TypeElement.Name).AssemblyQualifiedNameUltraShort;
                    context.LogError(string.Format("the target {0} is not resolvable. Please check the source assembly {1}", item.Mapper.MappingDestination.TypeElement.Name, assemblyName), "1", item);
                    return false;
                }
                else if (p1.Member == null) if (p1.Member == null)
                    {
                        context.LogError(string.Format("mismatch on the target name '{0}'.", p1.PropertyName), "1", item);
                        return false;
                    }

                if (item.TypeCast != CastType.Custom && p1.Member != null && !p1.Member.CanWrite())
                {
                    context.LogError("the target is not writable", "1", item);
                    return false;
                }

            }

           

            TestMember(context, item, itemName, itemType, source, p1.Member);

            if (!string.IsNullOrEmpty(item.CustomMethodName))
            {
                if (!regExCsharpName.IsMatch(item.CustomMethodName))
                {
                    context.LogError("the custom class method name is not a valid name", "1", item);
                    return false;
                }
                
            }

            return true;

        }

        public class MemberInfoDesc
        {
            public MemberInfo Member { get; set; }
            public string PropertyName { get; set; }
        }

        private IEnumerable<MemberInfoDesc> ResolveProperty(Type type, string propertyName)
        {

            if (type == null)
                yield break;

            if (propertyName == "this")
                yield return new MemberInfoDesc() { Member = type, PropertyName = propertyName };

            else
            {

                string[] tb = propertyName.Split('.');
                Type ttt = type;


                foreach (string name in tb)
                {

                    MemberInfo[] tt = ttt.GetMembers(name);

                    if (tt == null || tt.Length == 0)
                    {
                        yield return new MemberInfoDesc() { PropertyName = name };
                        break;
                    }

                    MemberInfoDesc m = GetMemberInfoDesc(ref ttt, name);

                    if (m != null)
                        yield return m;

                }

            }
        }

        



        private MemberInfoDesc GetMemberInfoDesc(ref Type ttt, string name)
        {

            foreach (MemberInfo m in ttt.GetMembers(name))
            {

                switch (m.MemberType)
                {

                    case MemberTypes.Field:
                    case MemberTypes.Property:
                        ttt = m.GetTypeFrom();
                        return new MemberInfoDesc() { Member = m, PropertyName = m.Name };

                    case MemberTypes.Method:
                        ParameterInfo[] ps = (m as MethodInfo).GetParameters();
                        if (ps.Count() > 0)
                            continue;
                        ttt = m.GetTypeFrom();
                        return new MemberInfoDesc() { Member = m, PropertyName = m.Name };

                    case MemberTypes.Constructor:
                    case MemberTypes.Custom:
                    case MemberTypes.Event:
                    case MemberTypes.NestedType:
                    case MemberTypes.TypeInfo:
                    default:
                        break;

                }

            }

            return null;

        }




        private void TestMember(ValidationContext context, ItemMap item, string propertyName, string propertyType, bool source, MemberInfo prop)
        {

            if (prop == null)
                context.LogError(string.Format("the type {0} for {1} can't be resolve", propertyName, "source"), "1", item);

            else
            {

                string tpe = ItemMap.FindTypeName(prop);


                using (Transaction t = Store.TransactionManager.BeginTransaction("Update Property"))
                {

                    Type type = prop.GetTypeFrom();

                    if (source)
                    {
                        item.SourceType = tpe;

                        item.SourceIsAbstract = type.IsAbstract;
                        item.SourceIsAnsiClass = type.IsAnsiClass;
                        item.SourceIsArray = type.IsArray;
                        item.SourceIsClass = type.IsClass;
                        item.SourceIsEnum = type.IsEnum;
                        item.SourceIsInterface = type.IsInterface;
                        item.SourceIsNested = type.IsNested;
                        item.SourceIsPublic = type.IsPublic;
                        item.SourceIsSealed = type.IsSealed;
                        item.SourceIsValueType = type.IsValueType;
                        item.SourceIsSerializable = type.IsSerializable;
                        item.SourceIsEnumerable = type.GetInterface("IEnumerable", true) != null;
                        if (item.SourceIsEnumerable)
                        {
                            Type typeEnumerable = FindItemFromIEnumerable(type);

                            if (typeEnumerable != null)
                                item.SourceItemType = typeEnumerable.AssemblyQualifiedName;

                            else
                                item.SourceItemType = string.Empty;
                            
                        }

                        item.SourceIsNullable = type.AssemblyQualifiedName.StartsWith("System.Nullable`1[[");

                    }
                    else
                    {
                        item.TargetType = tpe;

                        item.TargetIsAbstract = type.IsAbstract;
                        item.TargetIsAnsiClass = type.IsAnsiClass;
                        item.TargetIsArray = type.IsArray;
                        item.TargetIsClass = type.IsClass;
                        item.TargetIsEnum = type.IsEnum;
                        item.TargetIsInterface = type.IsInterface;
                        item.TargetIsNested = type.IsNested;
                        item.TargetIsPublic = type.IsPublic;
                        item.TargetIsSealed = type.IsSealed;
                        item.TargetIsValueType = type.IsValueType;
                        item.TargetIsSerializable = type.IsSerializable;
                        item.TargetIsEnumerable = type.GetInterface("IEnumerable", true) != null;
                        if (item.TargetIsEnumerable)
                        {

                            Type typeEnumerable = FindItemFromIEnumerable(type);

                            if (typeEnumerable != null)
                                item.TargetItemType = typeEnumerable.AssemblyQualifiedName;

                            else
                                item.TargetItemType = string.Empty;
                            
                        }
                        item.TargetIsNullable = type.AssemblyQualifiedName.StartsWith("System.Nullable`1[[");

                    }

                    t.Commit();
                }




            }
        }

        private Type FindItemFromIEnumerable(Type type)
        {

            Type[] types = type.GetInterfaces();
            foreach (Type t in types)
            {

                if (t.AssemblyQualifiedName.StartsWith("System.Collections.Generic.IEnumerable`1[["))
                {
                    Type types2 = t.GetGenericArguments().First();

                    return types2;
                }

                Type i = FindItemFromIEnumerable(t);

                if (i != null)
                    return i;
            }
            return null;
        }


        #endregion

        #region Test les cast

        private bool CheckProperties(ValidationContext context)
        {

            ItemTested = string.Empty;
            foreach (ItemMap item in this.ItemMaps)
            {

                this.ItemTested = item.Label;

                if (string.IsNullOrEmpty(item.SourceName) || string.IsNullOrEmpty(item.TargetName))
                    using (Transaction t = Store.TransactionManager.BeginTransaction("Disable ItemMap from " + item.Mapper.Name))
                    {
                        item.Enable = false;
                        t.Commit();
                    }


                if (item.Enable)
                {
                    if (!TestItemMap(context, item, item.SourceName, item.SourceType, true))
                        return false;

                    if (!TestItemMap(context, item, item.TargetName, item.TargetType, false))
                        return false;
                

                    CheckItemMap(context, item);
                
                }
            }

            ItemTested = string.Empty;
            return true;
        }

        private void CheckItemMap(ValidationContext context, ItemMap item)
        {

            if (item.SourceType != item.TargetType && !item.NeedMap)
            {
                TestItemMapWithCast(context, item);
            }
            else
            {
                if (item.TypeCast != CastType.Custom)
                {
                    if (item.TypeCast != CastType.None && !item.SourceIsEnumerable && !item.NeedMap)
                        using (Transaction t = Store.TransactionManager.BeginTransaction("Update ItemMap"))
                        {
                            item.TypeCast = CastType.None;
                            t.Commit();
                        }

                    else if (item.SourceName == "this" || item.TargetName == "this")
                    {
                        using (Transaction t = Store.TransactionManager.BeginTransaction("Update ItemMap"))
                        {
                            item.TypeCast = CastType.Custom;
                            t.Commit();
                        }
                    }
                }
            }

        }

        private void TestItemMapWithCast(ValidationContext context, ItemMap item)
        {
            // test pour l'enum

            if (item.SourceIsEnum)
                if (item.TypeCast != CastType.Custom && item.TypeCast != CastType.Explicit && item.TypeCast != CastType.EnumByLabel && item.TypeCast != CastType.EnumByValue)
                    context.LogError("For the property of type Enum the cast must be (Custom, EnumByLabel, EnumByValue or explicit)", "2", item);
            
            switch (item.TypeCast)
            {

                case CastType.IValueConverter:
                    ValidateTypeWithCastIValueconverter(context, item.SourceType, item.TargetType, item.Cast, item);
                    break;

                case CastType.Map:
                    ValidateMap(context, item);
                    break;

                case CastType.Explicit:
                    if (!item.SourceIsEnum)
                        ValidateTypeWithCastExplicit(context, item);
                    break;

                case CastType.IConverter:
                    ValidateTypeWithCastIConverter(context, item.SourceType, item.TargetType, item);
                    break;

                case CastType.Implicit:
                case CastType.Custom:
                case CastType.None:

                case CastType.EnumByLabel:
                    if (!item.SourceIsEnum && item.SourceType != "System.String")
                        context.LogError("with 'EnumByLabel' cast, the property source type must be String or Enum", "3", item);

                    if (!item.TargetIsEnum)
                        context.LogError("the 'EnumByLabel' cast must be used only for enum cast", "3", item);

                    break;

                case CastType.EnumByValue:
                    if (!item.TargetIsEnum)
                        context.LogError("the 'EnumByValue' cast must be used only for enum cast", "3", item);
                    break;

                default:
                    break;

            }
        }


        private void ValidateMap(ValidationContext context, ItemMap item)
        {

            if (!item.Enable)
                return;

            if (item.NeedMap && item.TypeCast != CastType.Map)
            {
                context.LogError("the property 'Type Cast' must be selected on Map", "1", item);
            }

            Mapper m = this.MappingModel.FindMapperFor(item.SourceType, item.TargetType);
            if (m == null)
            {
                context.LogError(string.Format("Missing mapper for convert '{0} to '{1}'", item.SourceType, item.TargetType), "1", item);

                if (this.MappingModel.FindTypeElementByClass(item.SourceType) == null)
                    context.LogError(string.Format("Missing container Element for the type '{0}", item.SourceType), "1", item);

                if (this.MappingModel.FindTypeElementByClass(item.TargetType) == null)
                    context.LogError(string.Format("Missing container Element for the type '{0}", item.TargetType), "1", item);
            }
            else
            {
                
            }

            //simple
            // IEnumerable
            // Generic

            //context.LogError(string.Format("the item map {0} need Map converter", item.SourceName), "1", item);

        }

        private void ValidateTypeWithCastIConverter(ValidationContext context, string typeSource, string typeTarget, ItemMap item)
        {

            Type filtre = typeof(Verbatim.CustomConverters.IConverter);
            Type t4 = this.MappingModel.FindType(item.Cast);
            if (t4 == null)
                return;

            Type[] t2 = t4.GetInterfaces();

            foreach (Type type in t2.Where(t => t.IsGenericType))
            {

                Type[] tb = type.GetGenericArguments();

                if (tb.Length < 2)
                    continue;

                string s = ItemMap.FindTypeName(tb[0]);
                string t = ItemMap.FindTypeName(tb[1]);

                if (s == item.SourceType && t == item.TargetType)
                {
                    item.CastWay = "Convert";
                    return;
                }
                if (s == item.TargetType && t == item.SourceType)
                {
                    item.CastWay = "ConvertBack";
                    return;
                }

                
            }

            context.LogError("the cast is not used to the types", "1", item);

        }

        private void ValidateTypeWithCastIValueconverter(ValidationContext context, string typeSource, string typeTarget, string typeCast, ItemMap item)
        {

            Type t1 = this.MappingModel.FindType(typeSource);
            Type t2 = this.MappingModel.FindType(typeTarget);
            Type t3 = this.MappingModel.FindType(typeCast);

            if (t1 == null)
                context.LogError(string.Format("the type {0} for {1} can't be resolve", typeSource, "source"), "1", item);

            else if (t2 == null)
                context.LogError(string.Format("the type {0} for {1} can't be resolve", typeTarget, "destination"), "1", item);

            else if (t3 == null)
                context.LogError(string.Format("the type {0} for {1} can't be resolve", typeCast, "property Cast"), "1", item);

            else
            {
                ValidateTypeWithCastIValueconverter(context, t1, t2, t3, item);
            }

        }

        private void ValidateTypeWithCastIValueconverter(ValidationContext context, Type typeSource, Type typeTarget, Type typeCast, ItemMap item)
        {

            ValueConversionAttribute attr = (ValueConversionAttribute)Attribute.GetCustomAttribute(typeCast, typeof(ValueConversionAttribute));

            if (attr != null)
            {
                if (attr.SourceType != typeSource && attr.SourceType != typeTarget)                
                    context.LogError(string.Format("the converter {0} isn't valid for the this mapping ", typeCast.Name), "2", item);
                
                if (attr.TargetType != typeSource && attr.TargetType != typeTarget)                
                    context.LogError(string.Format("the converter {0} isn't valid for the this mapping ", typeCast.Name), "2", item);
                
            }

        }

        private void ValidateTypeWithCastExplicit(ValidationContext context, ItemMap item)
        {
            context.LogMessage("The element uses an explicit cast, which can cause unexpected errors", "2", item);
        }
        
        #endregion

        #endregion ItemMap

        
    }
}
